add_subdirectory(kernelobj)

# 检测主机架构并转换为BPF目标架构
string(TOLOWER "${CMAKE_HOST_SYSTEM_PROCESSOR}" HOST_ARCH)
if(HOST_ARCH MATCHES "x86_64|amd64")
  set(BPF_TARGET_ARCH "x86")
elseif(HOST_ARCH MATCHES "aarch64")
  set(BPF_TARGET_ARCH "arm64")
else()
  set(BPF_TARGET_ARCH ${HOST_ARCH})
endif()

# 查找必要工具链
find_program(CLANG_EXE NAMES "clang")
find_program(LLVM_STRIP_EXE NAMES "llvm-strip")
find_program(BPFTOOL_EXE NAMES "bpftool")

# 生成vmlinux.h的自定义命令
add_custom_command(
  OUTPUT vmlinux.h
  COMMAND ${BPFTOOL_EXE} btf dump file /sys/kernel/btf/vmlinux format c > ${CMAKE_CURRENT_SOURCE_DIR}/vmlinux.h
  COMMENT "Generating vmlinux.h from kernel BTF"
  VERBATIM
)
add_custom_target(
  generate_vmlinux ALL
  DEPENDS vmlinux.h
)

# 生成BPF目标文件
add_custom_command(
  OUTPUT vfs_monitor.bpf.o
  COMMAND ${CLANG_EXE} -g -O2 -Wall -target bpf -D__TARGET_ARCH_${BPF_TARGET_ARCH} -c ${CMAKE_CURRENT_SOURCE_DIR}/vfs_monitor.bpf.c -o ${CMAKE_CURRENT_BINARY_DIR}/vfs_monitor.bpf.o
  COMMAND ${LLVM_STRIP_EXE} -g ${CMAKE_CURRENT_BINARY_DIR}/vfs_monitor.bpf.o
  DEPENDS vfs_monitor.bpf.c vmlinux.h
  COMMENT "Compiling BPF object"
)
add_custom_target(
  generate_o ALL
  SOURCES vfs_monitor.bpf.c
  DEPENDS vfs_monitor.bpf.o
)

# 生成BPF骨架头文件
add_custom_command(
  OUTPUT vfs_monitor.skel.h
  COMMAND ${BPFTOOL_EXE} gen skeleton ${CMAKE_CURRENT_BINARY_DIR}/vfs_monitor.bpf.o > ${CMAKE_CURRENT_SOURCE_DIR}/vfs_monitor.skel.h
  DEPENDS vfs_monitor.bpf.o
  COMMENT "Generating BPF skeleton"
)
add_custom_target(
  generate_skel ALL
  DEPENDS vfs_monitor.skel.h
)

find_package(leveldb REQUIRED)

find_package(Protobuf REQUIRED)
set(PROTO_FILES
    ${CMAKE_SOURCE_DIR}/common/fileevent.proto
)
PROTOBUF_GENERATE_CPP(PROTO_SRCS PROTO_HDRS ${PROTO_FILES})

find_package(PkgConfig)
pkg_check_modules(BPF REQUIRED libbpf)
pkg_check_modules(ELF REQUIRED libelf)
pkg_check_modules(ZLIB REQUIRED zlib)
pkg_check_modules(GUDEV REQUIRED gudev-1.0)

include_directories(${PROTOBUF_INCLUDE_DIRS})
include_directories(${BPF_INCLUDE_DIRS})
include_directories(${ELF_INCLUDE_DIRS})
include_directories(${ZLIB_INCLUDE_DIRS})
include_directories(${GUDEV_INCLUDE_DIRS})
include_directories(${CMAKE_CURRENT_SOURCE_DIR})
include_directories(${CMAKE_SOURCE_DIR}/common)

qt5_add_dbus_adaptor(GENERATED_SOURCES
    org.ukui.IndexFramework.Host.ServiceManager.xml
    servicemanager.h
    ServiceManager
    serviceadaptor
    ServiceAdaptor
)


add_executable(ukui-index-framework-host
    connection.cpp connection.h
    main.cpp
    servicemanager.cpp servicemanager.h
    vfsmonitor.cpp vfsmonitor.h
    fileidmapper.cpp fileidmapper.h
    org.ukui.IndexFramework.Host.ServiceManager.xml
    data/org.ukui.IndexFramework.conf
    ${GENERATED_SOURCES}
    #vfs_monitor.skel.h #编译时生成
    ${PROTO_SRCS} ${PROTO_HDRS}
)

target_link_libraries(ukui-index-framework-host PRIVATE
    Qt::Core
    Qt::DBus
    Qt::Network
    ${BPF_LIBRARIES}
    ${ELF_LIBRARIES}
    ${ZLIB_LIBRARIES}
    ${PROTOBUF_LIBRARIES}
    ${GUDEV_LIBRARIES}
    leveldb
)

# 确保构建顺序
add_dependencies(ukui-index-framework-host
  generate_skel
  generate_o
  generate_vmlinux
)

# 清理规则
set_directory_properties(PROPERTIES ADDITIONAL_CLEAN_FILES
  "vfs_monitor.bpf.o;vfs_monitor.skel.h;vmlinux.h"
)

install(TARGETS ukui-index-framework-host
    RUNTIME DESTINATION ${GNU_INSTALL_BINDIR}
)

install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/data/org.ukui.IndexFramework.conf
  DESTINATION /usr/share/dbus-1/system.d/
  PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ)

install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/data/org.ukui.IndexFramework.service
  DESTINATION /usr/share/dbus-1/services/
  PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ)

install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/data/ukui-index-framework-host.service
  DESTINATION /usr/lib/systemd/system/
  PERMISSIONS OWNER_READ OWNER_WRITE GROUP_READ WORLD_READ)
